using DG.Tweening;
using Sirenix.OdinInspector;
using System;
using System.Globalization;
using TMPro;
using UnityEngine;
namespace Custom.Daily.Toolkit
{
    [AddComponentMenu("日常工具包/日期选择器")]
    public class CalendarSelectManager : MonoBehaviour
    {
        [FoldoutGroup("物体引用"), LabelText("元素挂载父对象")]
        public Transform dayParent;
        [FoldoutGroup("物体引用"), LabelText("输入框面板")]
        public TMP_InputField inputField;
        [FoldoutGroup("物体引用"), LabelText("下拉面板")]
        public RectTransform dropDownPanel;
        [FoldoutGroup("物体引用"), LabelText("选择的日期文本")]
        public TMP_Text calendarText;

        [LabelText("当前选择的日期")]
        public Calendar selectCalendar; // 当前选择的日期
        private Vector2 orginHeight;
        private void Start()
        {
            selectCalendar = new();
            orginHeight = dropDownPanel.sizeDelta;
        }

        #region Public Function
        /// <summary>
        /// 按钮点击
        /// </summary>
        /// <param name="val"></param>
        public void CalendarBtnClick(int val)
        {
            CalendarBtnType btnType = (CalendarBtnType)val;
            switch (btnType)
            {
                case CalendarBtnType.PrevYear:
                    int prevYear = Mathf.Max(0, selectCalendar.year - 1);
                    int prevYearDays = CalendarSelectTools.GetDayByYearMonth(prevYear, selectCalendar.month);
                    SetCalendar(prevYear, selectCalendar.month, Mathf.Min(selectCalendar.day, prevYearDays));
                    break;
                case CalendarBtnType.PrevMonth:
                    int[] prevMonth = CalendarSelectTools.GetPrevYearMonth(selectCalendar.year, selectCalendar.month);
                    int prevMonthDays = CalendarSelectTools.GetDayByYearMonth(prevMonth[0], prevMonth[1]);
                    SetCalendar(prevMonth[0], prevMonth[1], Mathf.Min(selectCalendar.day, prevMonthDays));
                    break;
                case CalendarBtnType.NextMonth:
                    int[] nextMonth = CalendarSelectTools.GetNextYearMonth(selectCalendar.year, selectCalendar.month);
                    int nextMonthDays = CalendarSelectTools.GetDayByYearMonth(nextMonth[0], nextMonth[1]);
                    SetCalendar(nextMonth[0], nextMonth[1], Mathf.Min(selectCalendar.day, nextMonthDays));
                    break;
                case CalendarBtnType.NextYear:
                    int nextYear = Mathf.Max(0, selectCalendar.year + 1);
                    int nextYearDays = CalendarSelectTools.GetDayByYearMonth(nextYear, selectCalendar.month);
                    SetCalendar(nextYear, selectCalendar.month, Mathf.Min(selectCalendar.day, nextYearDays));
                    break;
            }
        }
        /// <summary>
        /// 输入框值改变事件
        /// </summary>
        public void InputFieldValueChanged(string val)
        {
            string[] formats = new string[] { "yyyy-M-d", "yyyy-MM-dd" };
            CultureInfo culture = CultureInfo.InvariantCulture;
            if (DateTime.TryParseExact(val, formats, culture, DateTimeStyles.None, out DateTime result))
            {
                SetCalendar(result.Year, result.Month, result.Day);
            }
        }
        /// <summary>
        /// 输入框被点击时
        /// </summary>
        public void InputFieldClick()
        {
            Expand();
        }
        /// <summary>
        /// 输入框失去焦点
        /// </summary>
        public void InputLostFocus()
        {
            PutAway();
        }
        /// <summary>
        /// 元素被点击
        /// </summary>
        public void DayToggleClick(bool val, Calendar calendar)
        {
            if (val)
            {
                SetCalendar(calendar);
            }
            else
            {
                if (selectCalendar.isEquals(calendar))
                {
                    SetCalendar(calendar.year, calendar.month, 0);
                }
            }
        }
        #endregion


        #region Private Function

        /// <summary>
        /// 展开动画
        /// </summary>
        private void Expand()
        {
            if (!dropDownPanel.gameObject.activeSelf)
            {
                inputField.interactable = false;

                dropDownPanel.sizeDelta = new(orginHeight.x, 0f);
                dropDownPanel.gameObject.SetActive(true);
                dropDownPanel.DOSizeDelta(orginHeight, 0.2f).OnComplete(() => inputField.interactable = true);

                string text = inputField.text;
                string[] formats = new string[] { "yyyy-M-d", "yyyy-MM-dd" };
                CultureInfo culture = CultureInfo.InvariantCulture;
                int tmpValue = 999;
                if (!DateTime.TryParseExact(text, formats, culture, DateTimeStyles.None, out DateTime result))
                {
                    tmpValue = 0;
                    result = DateTime.Now;
                }
                SetCalendar(result.Year, result.Month, Mathf.Min(tmpValue, result.Day));
            }
        }
        /// <summary>
        /// 收起动画
        /// </summary>
        private void PutAway()
        {
            if (dropDownPanel.gameObject.activeSelf)
            {
                inputField.interactable = false;
                dropDownPanel.DOSizeDelta(new(orginHeight.x, 0f), 0.2f).OnComplete(() =>
                {
                    dropDownPanel.gameObject.SetActive(false);
                    inputField.interactable = true;

                    string text = inputField.text;
                    string[] formats = new string[] { "yyyy-M-d", "yyyy-MM-dd" };
                    CultureInfo culture = CultureInfo.InvariantCulture;
                    if (!DateTime.TryParseExact(text, formats, culture, DateTimeStyles.None, out DateTime result))
                    {
                        inputField.text = "日期格式输入错误!";
                        selectCalendar.SetValue(0, 0, 0);
                    }
                });
            }
        }
        /// <summary>
        /// 设置选择的日期
        /// </summary>
        private void SetCalendar(Calendar calendar)
        {
            SetCalendar(calendar.year, calendar.month, calendar.day);
        }
        /// <summary>
        /// 设置选择的日期
        /// </summary>
        private void SetCalendar(int year, int month, int day)
        {
            if (selectCalendar.isEquals(year, month, day)) return;
            if (year != selectCalendar.year || month != selectCalendar.month)
            {
                RendCalendarData(year, month);
            }
            selectCalendar.SetValue(year, month, day);
            calendarText.text = $"{year}年{month}月";
            RenderInputField();
            RenderDayList();
        }
        /// <summary>
        /// 更新Input文本
        /// </summary>
        private void RenderInputField()
        {
            string[] formats = new string[] { "yyyy-M-d", "yyyy-MM-dd" };
            CultureInfo culture = CultureInfo.InvariantCulture;
            if (DateTime.TryParseExact(inputField.text, formats, culture, DateTimeStyles.None, out DateTime result))
            {
                if (selectCalendar.isEquals(result.Year, result.Month, result.Day)) return;
            }
            if(selectCalendar.day == 0)
            {
                inputField.text = string.Empty;
            }
            else
            {
                inputField.text = $"{selectCalendar.year}-{selectCalendar.month}-{selectCalendar.day}";
            }
        }
        /// <summary>
        /// 更新所有点击元素的状态
        /// </summary>
        private void RenderDayList()
        {
            for (int i = 0; i < dayParent.childCount; i++)
            {
                Transform trans = dayParent.GetChild(i);
                ToggleEvent toggleEvent = trans.GetComponent<ToggleEvent>();
                ToggleController toggle = trans.GetComponent<ToggleController>();
                if (selectCalendar.isEquals(toggleEvent.calendar))
                {
                    toggle.isOn = true;
                }
                else
                {
                    toggle.isOn = false;
                }
            }
        }
        /// <summary>
        /// 渲染下拉框中的日期列表
        /// </summary>
        private void RendCalendarData(int year, int month)
        {
            int weekNum = CalendarSelectTools.GetFirstDayOfWeek(year,month);
            int monthDays = CalendarSelectTools.GetDayByYearMonth(year,month);

            int[] prevMonth = CalendarSelectTools.GetPrevYearMonth(year,month);
            int prevMonthdays = CalendarSelectTools.GetDayByYearMonth(prevMonth[0], prevMonth[1]);

            int[] nextMonth = CalendarSelectTools.GetNextYearMonth(year, month);

            int count = 0;
            for (int i = weekNum; i > 1; i--)
            {
                int dayNum = prevMonthdays - (i - 2);
                Transform trans = dayParent.GetChild(count);
                trans.GetComponent<ToggleEvent>().calendar = new Calendar(prevMonth[0], prevMonth[1], dayNum);
                TMP_Text txt = trans.GetChild(2).GetComponent<TMP_Text>();
                txt.text = $"{dayNum}";
                txt.color = new Color(1f, 1f, 1f, 0.15f);
                count++;
            }

            for (int i = 1; i <= monthDays; i++)
            {
                Transform trans = dayParent.GetChild(count);
                trans.GetComponent<ToggleEvent>().calendar = new Calendar(year, month, i);
                TMP_Text txt = trans.GetChild(2).GetComponent<TMP_Text>();
                txt.text = $"{i}";
                txt.color = new Color(1f, 1f, 1f, 1f);
                count++;
            }

            int tmp = count;
            for (int i = 0; i < dayParent.childCount - tmp; i++)
            {
                int dayNum = i + 1;
                Transform trans = dayParent.GetChild(count);
                trans.GetComponent<ToggleEvent>().calendar = new Calendar(nextMonth[0], nextMonth[1], dayNum);
                TMP_Text txt = trans.GetChild(2).GetComponent<TMP_Text>();
                txt.text = $"{dayNum}";
                txt.color = new Color(1f, 1f, 1f, 0.15f);
                count++;
            }
        }
        #endregion

    }
    [Serializable]
    public struct Calendar
    {
        [LabelText("年")]
        public int year;
        [LabelText("月")]
        public int month;
        [LabelText("日")]
        public int day;
        public Calendar(int year, int month, int day)
        {
            this.year = year;
            this.month = month;
            this.day = day;
        }
        public void SetValue(int year, int month, int day)
        {
            this.year = year; this.month = month; this.day = day;
        }
        public bool isEquals(int year, int month, int day)
        {
            return this.year == year && this.month == month && this.day == day;
        }
        public bool isEquals(Calendar c)
        {
            return this.year == c.year && this.month == c.month && this.day == c.day;
        }
    }
    [Serializable]
    public enum CalendarBtnType
    {
        [LabelText("上一年")]
        PrevYear,
        [LabelText("上一个月")]
        PrevMonth,
        [LabelText("下一个月")]
        NextMonth,
        [LabelText("下一年")]
        NextYear
    }

}
